﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
using System.Diagnostics;

namespace Mandarine.MVVM.Command
{
    /// <summary>
    /// コマンドの中継クラスを提供します
    /// 
    /// </summary>
    /// <typeparam name="T">アクションに渡す型パラメタを指定します</typeparam>
    public class RelayCommand<T> : ICommand
    {
        protected Action<T> _execute;
        protected Predicate<T> _canExecute;

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="execute"></param>
        public RelayCommand(Action<T> execute)
            : this(execute, null)
        { }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="execute"></param>
        /// <param name="canExecute"></param>
        public RelayCommand(Action<T> execute, Predicate<T> canExecute)
        {
            //if (execute == null)
            //    throw new ArgumentNullException("execute");

            _execute = execute;
            _canExecute = canExecute;
        }
        /// <summary>
        /// このコマンドが実行できるか否かを検査します
        /// </summary>
        /// <param name="parameter"></param>
        /// <returns></returns>
        [DebuggerStepThrough]
        public bool CanExecute(Object parameter)
        {
            return _canExecute == null || _canExecute((T)parameter);
        }

        public event EventHandler CanExecuteChanged;
        /// <summary>
        /// CanExecutechangedが変更された際のイベントを発火します
        /// </summary>
        public void RaiseCanExecuteChanged()
        {
            var handler = CanExecuteChanged;
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }

        /// <summary>
        /// コマンドを実行します
        /// </summary>
        /// <param name="parameter"></param>
        public void Execute(Object parameter)
        {
            var dispatcher = Deployment.Current.Dispatcher;
            if (dispatcher.CheckAccess())
            {
                _execute((T)parameter);
            }
            else
            {
                dispatcher.BeginInvoke(_execute, (T)parameter);
            }
        }
    }
}
